home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / BBS-Archive / Comm / AmiTCP30b2.lha / src / netlib / rcmd.c < prev    next >
C/C++ Source or Header  |  1994-05-02  |  11KB  |  349 lines

  1. RCS_ID_C = "$Id: rcmd.c,v 3.4 1994/05/02 19:36:09 jraja Exp $";
  2. /*
  3.  * rcmd.c --- rcmd() for AmiTCP/IP and usergroup.library
  4.  *
  5.  * Author: ppessi <Pekka.Pessi@hut.fi>
  6.  *
  7.  * Copyright © 1993 AmiTCP/IP Group, <AmiTCP-Group@hut.fi>
  8.  *                  Helsinki University of Technology, Finland.
  9.  *
  10.  * Created      : Sun Oct 31 21:49:44 1993 ppessi
  11.  * Last modified: Sat Apr  2 14:49:39 1994 jraja
  12.  *
  13.  * $Log: rcmd.c,v $
  14.  * Revision 3.4  1994/05/02  19:36:09  jraja
  15.  * Fixed the type of the getpid() macro.
  16.  *
  17.  * Revision 3.3  1994/04/12  20:50:04  jraja
  18.  * Changed to use CloseSocket() and IoctlSocket() (again), made the guessing
  19.  * the socket count in the select() call to calculate the needed value.
  20.  *
  21.  * Revision 3.1  1994/04/02  11:51:59  jraja
  22.  * Moved ioctl() and close() defines inside ifdef DEBUGGING, changed herror()
  23.  * to be called when not DEBUGGING.
  24.  *
  25.  * Revision 1.3  1994/02/03  19:23:54  ppessi
  26.  * Fixed documentation and prototypes
  27.  *
  28.  * Revision 1.2  1994/01/21  14:40:35  ppessi
  29.  * Added autodoc
  30.  *
  31.  * Revision 1.1  1994/01/21  12:43:36  ppessi
  32.  * Initial revision
  33.  */
  34.  
  35. /*
  36.  * Copyright (c) 1983 Regents of the University of California.
  37.  * All rights reserved.
  38.  *
  39.  * Redistribution and use in source and binary forms, with or without
  40.  * modification, are permitted provided that the following conditions
  41.  * are met:
  42.  * 1. Redistributions of source code must retain the above copyright
  43.  *    notice, this list of conditions and the following disclaimer.
  44.  * 2. Redistributions in binary form must reproduce the above copyright
  45.  *    notice, this list of conditions and the following disclaimer in the
  46.  *    documentation and/or other materials provided with the distribution.
  47.  * 3. All advertising materials mentioning features or use of this software
  48.  *    must display the following acknowledgement:
  49.  *    This product includes software developed by the University of
  50.  *    California, Berkeley and its contributors.
  51.  * 4. Neither the name of the University nor the names of its contributors
  52.  *    may be used to endorse or promote products derived from this software
  53.  *    without specific prior written permission.
  54.  *
  55.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  56.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  57.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  58.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  59.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  60.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  61.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  62.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  63.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  64.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  65.  * SUCH DAMAGE.
  66.  */
  67.  
  68. #if __SASC
  69. #include <proto/dos.h>
  70. #include <proto/socket.h>
  71. #include <proto/exec.h>
  72. #elif __GNUC__
  73. #include <inline/dos.h>
  74. #include <inline/socket.h>
  75. #include <inline/exec.h>
  76. #else
  77. #include <clib/dos_protos.h>
  78. #include <clib/socket_protos.h>
  79. #include <clib/exec_protos.h>
  80. #endif
  81.  
  82. #include <sys/param.h>
  83. #include <sys/ioctl.h>
  84. #include <sys/socket.h>
  85. #include <sys/stat.h>
  86. #include <netinet/in.h>
  87. #include <arpa/inet.h>
  88. #include <signal.h>
  89. #include <fcntl.h>
  90. #include <netdb.h>
  91. #include <pwd.h>
  92. #include <errno.h>
  93. #include <stdio.h>
  94. #include <ctype.h>
  95.  
  96. #include <unistd.h>
  97. #include <string.h>
  98.  
  99. #ifdef ioctl
  100. #undef ioctl
  101. #endif
  102. #ifdef close
  103. #undef close
  104. #endif
  105. #define ioctl IoctlSocket
  106. #define close CloseSocket
  107. #define getpid() ((pid_t)FindTask(0L))
  108.  
  109. #ifdef DEBUGGING
  110. #include "dosio.h"
  111. #define fprintf FPrintf
  112. #define stderr (Output())
  113. #define herror(x) fprintf(stderr, "%s: not found\n", (x)) 
  114. #define DB(x) (x)
  115. #else
  116. #define DB(x) ;
  117. #endif
  118.  
  119. /****** net.lib/rcmd *********************************************************
  120.  
  121.     NAME
  122.         rcmd, rresvport - routines for returning a stream to a remote command
  123.  
  124.     SYNOPSIS
  125.         #include <clib/socket_protos.h>
  126.  
  127.         int rcmd(char **ahost, int inport, const char *locuser, 
  128.                  const char *remuser, const char *cmd, int *fd2p);
  129.  
  130.         int rresvport(int *port);
  131.  
  132.     FUNCTION
  133.         The rcmd() function is used by the super-user to execute a command on
  134.         a remote machine using an authentication scheme based on reserved port
  135.         numbers.  The rresvport() function returns a descriptor to a socket
  136.         with an address in the privileged port space.  Both functions are
  137.         present in the same file and are used by the rsh command (among
  138.         others).
  139.  
  140.         The rcmd() function looks up the host *ahost using gethostbyname(),
  141.         returning -1 if the host does not exist.  Otherwise *ahost is set to
  142.         the standard name of the host and a connection is established to a
  143.         server residing at the well-known Internet port inport.
  144.  
  145.         If the connection succeeds, a socket in the Internet domain of type
  146.         SOCK_STREAM is returned to the caller, and given to the remote command
  147.         as stdin and stdout. If fd2p is non-zero, then an auxiliary channel to
  148.         a control process will be set up, and a descriptor for it will be
  149.         placed in *fd2p. The control process will return diagnostic output
  150.         from the command (unit 2) on this channel, and will also accept bytes
  151.         on this channel as being UNIX signal numbers, to be forwarded to the
  152.         process group of the command.  If fd2p is 0, then the stderr (unit 2
  153.         of the remote command) will be made the same as the stdout and no
  154.         provision is made for sending arbitrary signals to the remote process,
  155.         although you may be able to get its attention by using out-of-band
  156.         data.
  157.  
  158.         The protocol is described in detail in netutil/rshd.
  159.  
  160.         The rresvport() function is used to obtain a socket with a privileged
  161.         address bound to it.  This socket is suitable for use by rcmd() and
  162.         several other functions.  Privileged Internet ports are those in the
  163.         range 0 to 1023.  Only the super-user is allowed to bind an address of
  164.         this sort to a socket.
  165.  
  166.     DIAGNOSTICS
  167.         The rcmd() function returns a valid socket descriptor on success.  It
  168.         returns -1 on error and prints a diagnostic message on the standard
  169.         error.
  170.  
  171.         The rresvport() function returns a valid, bound socket descriptor on
  172.         success.  It returns -1 on error with the global value errno set
  173.         according to the reason for failure.  The error code EAGAIN is
  174.         overloaded to mean `All network ports in use.'
  175.  
  176.     SEE ALSO
  177.         netutil/rlogin,  netutil/rsh,  rexec(),  netutil/rexecd,
  178.         netutil/rlogind, netutil/rshd
  179.  
  180. ******************************************************************************
  181. */
  182.  
  183. #include <clib/netlib_protos.h>
  184.  
  185. int
  186. rcmd(char **ahost,
  187.      int rport,
  188.      const char *locuser, 
  189.      const char *remuser, 
  190.      const char *cmd,
  191.      int *fd2p)            /* Socket for stderr  */
  192. {
  193.   int s, timo = 1;
  194.   pid_t pid;
  195.   struct sockaddr_in sin, from;
  196.   char c;
  197.   int lport = IPPORT_RESERVED - 1;
  198.   struct hostent *hp;
  199.   fd_set reads;
  200.  
  201.   pid = getpid();
  202.   hp = gethostbyname(*ahost);
  203.   if (hp == 0) {
  204.     herror(*ahost);
  205.     errno = EADDRNOTAVAIL;
  206.     return (-1);
  207.   }
  208.   *ahost = hp->h_name;
  209.  
  210.   for (;;) {
  211.     s = rresvport(&lport);
  212.     if (s < 0) {
  213.       DB(errno == EAGAIN ? 
  214.      fprintf(stderr, "socket: All ports in use\n")
  215.      : perror("rcmd: socket"));
  216.       return (-1);
  217.     }
  218.     ioctl(s, FIOSETOWN, (caddr_t)&pid);
  219.     sin.sin_len = sizeof(sin);
  220.     sin.sin_family = hp->h_addrtype;
  221.     bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, hp->h_length);
  222.     sin.sin_port = rport;
  223.     if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
  224.       break;
  225.     (void) close(s);
  226.     if (errno == EADDRINUSE) {
  227.       lport--;
  228.       continue;
  229.     }
  230.     if (errno == ECONNREFUSED && timo <= 16) {
  231.       sleep(timo);
  232.       timo *= 2;
  233.       continue;
  234.     }
  235.     if (hp->h_addr_list[1] != NULL) {
  236.       DB(int oerrno = errno);
  237.  
  238.       DB(fprintf(stderr, "connect to address %s: ", inet_ntoa(sin.sin_addr)));
  239.       DB(errno = oerrno);
  240.       DB(perror(""));
  241.       hp->h_addr_list++;
  242.       bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, hp->h_length);
  243.       DB(fprintf(stderr, "Trying %s...\n", inet_ntoa(sin.sin_addr)));
  244.       continue;
  245.     }
  246.     DB(perror(hp->h_name));
  247.     return (-1);
  248.   }
  249.  
  250.   lport--;
  251.   if (fd2p == 0) {
  252.     send(s, "", 1, 0);
  253.     lport = 0;
  254.   } else {
  255.     char num[8];
  256.     long s2 = rresvport(&lport), s3;
  257.     long len = sizeof (from);
  258.  
  259.     if (s2 < 0)
  260.       goto bad;
  261.     listen(s2, 1);
  262.     (void) sprintf(num, "%d", lport);
  263.     if (send(s, num, strlen(num)+1, 0) != strlen(num)+1) {
  264.       DB(perror("write: setting up stderr"));
  265.       (void) close(s2);
  266.       goto bad;
  267.     }
  268.     FD_ZERO(&reads);
  269.     FD_SET(s, &reads);
  270.     FD_SET(s2, &reads);
  271.     errno = 0;
  272.     if (select(((s > s2) ? s : s2) + 1,
  273.            &reads, 0, 0, 0) < 1 || !FD_ISSET(s2, &reads)) {
  274.       DB(errno != 0 ?
  275.      perror("select: setting up stderr")
  276.      :
  277.      fprintf(stderr, "select: protocol failure in circuit setup.\n"));
  278.       (void) close(s2);
  279.       goto bad;
  280.     }
  281.     s3 = accept(s2, (struct sockaddr *)&from, &len);
  282.     (void) close(s2);
  283.     if (s3 < 0) {
  284.       DB(perror("accept"));
  285.       lport = 0;
  286.       goto bad;
  287.     }
  288.     *fd2p = s3;
  289.     from.sin_port = ntohs((u_short)from.sin_port);
  290.     if (from.sin_family != AF_INET ||
  291.     from.sin_port >= IPPORT_RESERVED ||
  292.     from.sin_port < IPPORT_RESERVED / 2) {
  293.       DB(fprintf(stderr, "socket: protocol failure in circuit setup.\n"));
  294.       goto bad2;
  295.     }
  296.   }
  297.   (void) send(s, locuser, strlen(locuser) + 1, 0);
  298.   (void) send(s, remuser, strlen(remuser) + 1, 0);
  299.   (void) send(s, cmd, strlen(cmd) + 1, 0);
  300.   if (recv(s, &c, 1, 0) != 1) {
  301.     DB(perror(*ahost));
  302.     goto bad2;
  303.   }
  304.   if (c != 0) {
  305.     while (recv(s, &c, 1, 0) == 1) {
  306.       (void) write(2, &c, 1);
  307.       if (c == '\n')
  308.     break;
  309.     }
  310.     goto bad2;
  311.   }
  312.  
  313.   return (s);
  314.  bad2:
  315.   if (lport)
  316.     (void) close(*fd2p);
  317.  bad:
  318.   (void) close(s);
  319.   return (-1);
  320. }
  321.  
  322. int rresvport(int *alport)
  323. {
  324.   struct sockaddr_in sin;
  325.   int s;
  326.  
  327.   sin.sin_len = sizeof(sin);
  328.   sin.sin_family = AF_INET;
  329.   sin.sin_addr.s_addr = INADDR_ANY;
  330.   s = socket(AF_INET, SOCK_STREAM, 0);
  331.   if (s < 0)
  332.     return (-1);
  333.   for (;;) {
  334.     sin.sin_port = htons((u_short)*alport);
  335.     if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) >= 0)
  336.       return (s);
  337.     if (errno != EADDRINUSE) {
  338.       (void) close(s);
  339.       return (-1);
  340.     }
  341.     (*alport)--;
  342.     if (*alport == IPPORT_RESERVED/2) {
  343.       (void) close(s);
  344.       errno = EAGAIN;        /* close */
  345.       return (-1);
  346.     }
  347.   }
  348. }
  349.